/**  
* @Title: BaseDaoImpl.java
* @Package com.test.dao.base
* @Description: TODO 通用DAO实现类
* @author daiji  
* @date 2015-9-6 下午3:24:31
* @version V1.0  
*/
package base.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.internal.CriteriaImpl;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.stereotype.Repository;

import base.entity.Page;

@Repository("baseDaoImpl")
public class BaseDaoImpl implements IBaseDao{
	
	@Resource
	private SessionFactory sessionFactory;
	
	@Resource
	private HibernateTemplate hibernateTemplate;
	
	public  BaseDaoImpl() {
		//System.out.println("---create BaseDaoImpl---");
	}
	
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	protected void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public Session getSession() {
		Session session = sessionFactory.getCurrentSession();
		return session;
	}
	
	public <T> T save(T t) {
		this.getSession().save(t);
		return t;
	}

	public <T> T saveOrUpdate(T t) {
		this.getSession().saveOrUpdate(t);
		return t;
	}

	public <T> List<T> save(Collection<T> list) {
		for (T t : list) {
			this.save(t);
		}
		return new ArrayList<T>(list);
	}

	public int delete(Object t) {
		this.getSession().delete(t);
		return 1;
	}

	@SuppressWarnings("rawtypes")
	public int delete(Class c, Object id) throws Exception {
		return this.executeHql("delete from "+c.getName()+" where ID = ?", new Object[]{id});
	}

	@SuppressWarnings("rawtypes")
	public int delete(Collection list) {
		int i = 0;
		for (Object object : list) {
			this.delete(object);
			i++;
		}
		return i;
	}

	@SuppressWarnings("unchecked")
	public <T> T getById(Class<T> c, Serializable id) {
		return (T) this.getSession().get(c, id);
	}

	public <T> T findOne(String hql, Object[] params) throws Exception {
		List<T> list = this.find(hql, params);
		if(list.size() == 1){
			return list.get(0);
		}
		return null;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T> List<T> getByIdList(Class<T> c, Collection ids) {
		Criteria criteria = getSession().createCriteria(c);
		return criteria.add(Restrictions.in("id", ids)).list();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> get(Class<T> c) {
		return this.getSession().createQuery("from "+c.getName()).list();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> find(String hql, Object[] params) throws Exception  {
		Session session = this.getSession();
		Query q = session.createQuery(hql);
		int paramLength = params.length;
		for (int i = 0; i < paramLength; i++) {
			q.setParameter(i, params[i]);
		}
		return q.list();
	}

	@SuppressWarnings("unchecked")
	public <T> Page<T> find(String hql, Object[] params, int pageNo,
			int pageSize) throws Exception {
		if (pageNo < 1) {
			pageNo = 1;
		}
		if(pageSize < 1){
			pageSize = 10;
		}
		Query q = this.getSession().createQuery(hql);
		int paramLength = params.length;
		if (paramLength > 0) {
			for (int i = 0; i < paramLength; i++) {
				q.setParameter(i, params[i]);
			}
		}
		long totalRow = this.countHql(hql, params);
		Page<T> page = null;
		page = new Page<T>((int) totalRow, pageSize, pageNo);
		List<T> datas = q.setFirstResult((pageNo - 1) * pageSize)
				.setMaxResults(pageSize).list();
		page.setDatas(datas);
		return page;
	}

	public long countHql(String hql, Object[] params) throws Exception {
		int formIndex = hql.indexOf("from");
		String countHql = "select count(*) "+hql;
		if(formIndex > 0){
			countHql = "select count(*) "+hql.substring(formIndex);
		}
		Query countq = this.getSession().createQuery(countHql);
		int paramLength = params.length;
		if (paramLength > 0) {
			for (int i = 0; i < paramLength; i++) {
				countq.setParameter(i, params[i]);
			}
		}
		long num =  (Long) countq.uniqueResult();
		return num;
	}

	public int executeHql(String hql, Object[] params) throws Exception {
		Query q = this.getSession().createQuery(hql);
		int paramLength = params.length;
		if (paramLength > 0) {
			for (int i = 0; i < paramLength; i++) {
				q.setParameter(i, params[i]);
			}
		}
		return q.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findByCriteria(DetachedCriteria criteria) {
		Criteria c = criteria.getExecutableCriteria(this.getSession());
		return c.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> Page<T> findByCriteria(DetachedCriteria criteria, Integer pageNo,
			Integer pageSize) {
		if ( pageNo < 1) {
			pageNo = 1;
		}
		if ( pageSize < 1) {
			pageSize = 10;
		}
		Criteria criteria2=criteria.getExecutableCriteria(this.getSession());
        CriteriaImpl criteriaImpl=(CriteriaImpl) criteria2;
        Projection projection=criteriaImpl.getProjection();
        Long totalRow=(java.lang.Long) criteria2.setProjection(Projections.rowCount()).uniqueResult();
        criteria2.setProjection(projection);
        if(projection==null){
            criteria2.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }
		List<T> datas =  (List<T>) hibernateTemplate.findByCriteria(criteria, (pageNo - 1) * pageSize, pageSize);
		Page<T> page = new Page<T>( totalRow.intValue(), pageSize, pageNo);
		page.setDatas(datas);
		return page;
	}

}
